import { Spin, message } from 'antd'
import React, { Component } from 'react'
import _ from 'lodash'
import InputWidget from '../InputWidget'
import { getFormProps } from '@/utils/formPropsUtil'
import RadioWidget from '../RadioWidget'
import formValidate from '@/service/validate/formValidate'
import FlexBox from '../FlexBox'
import TextAreaWidget from '../TextAreaWidget'
import Debug from '../Debug'
import { getTemplateByCode } from '@/service/schema/schemaService'
import { getDocumentById, updateDocumentById, createDocument } from '@/service/document/documentService'
import Button from '../Button'
import consoleUtil from '@/utils/consoleUtil'
import DateWidget from '../DateWidget'

/**
 * 表单解析器
 * @author liu_jshan
 * @date 20241005
 * 
 * @props
 *  1.onFormChange(originalFormData, changeFormData)
 *      表单变化时触发
 *      originalFormData变化前的表单数据，changeFormData变化的表单数据
 *  2.initFormData({*})
 *      表单数据初始化的入口之一
 *  3.validate(formData)
 *      自定义表单校验方法
 *  4.onDataCreate(childState, type)
 *      调用saveHandler方法成功后触发
 *      childState表单组件的state，type保存的类型 new：新建 modify：修改
 *  5.beforeCreate(formData)
 *      校验完成后保存前的回调函数
 *      formData 表单数据
 */
class FormWidget extends Component {

    constructor(props) {
        super(props)
        this.state = {
            formKey: new Date().getTime(),
            formData: {}, //表单的值
            auditFormData: {}, //经过审计的表单数据
            schema: {}, //表单配置信息
            propertyArray: [], //表单对象数组
            buttons: [], //按钮配置数组
            loading: true
        }
        this.refMap = {} //所有引用的键值对
    }

    async componentDidMount() {

        if (!this.props.code) {
            message.warning('未配置表单模板标识！')
            return
        }

        let formData = {} //表单数据的值

        //接收initFromData方法初始化
        formData = { ...formData, ...this.props.initFormData }

        //获取接口返回的表单数据
        let auditFormData = {}
        if (this.props.id && this.props.serviceName && this.props.collectionName) {
            const response = await getDocumentById({
                id: this.props.id,
                collectionName: this.props.collectionName,
                serviceName: this.props.serviceName
            })
            if (response && response.data) {
                auditFormData = response.data
            }
        }
        formData = { ...formData, ...auditFormData.content }


        // 获取表单模板内容
        let template = {}
        try {
            template = await getTemplateByCode(this.props.code)
        } catch (e) {
            consoleUtil.error('获取表单模板失败', e)
            return
        }
        if (!template || !template.content) {
            consoleUtil.error('获取表单模板失败')
            return
        }
        let schema = _.get(_.cloneDeep(template), 'content', {})

        //表单按钮属性逻辑
        const buttons = _.get(schema, 'buttons', [])

        //表单字段属性逻辑
        const properties = _.get(schema, 'properties', {}) //表单字段属性对象
        //表单字段属性数组
        const propertyArray = Object.keys(properties).map(key => {
            //获取表单默认值
            const defaultValue = getFormProps(_.get(properties[key], 'widgetConfig.defaultValue', null), this, `${key}的默认值获取失败`)
            if (defaultValue !== null) {
                formData[key] = defaultValue
            }
            return {
                ...properties[key],
                key
            }
        }).sort((a, b) => (a.order || -1) - (b.order || -1))

        this.setState({
            schema,
            formData,
            auditFormData,
            propertyArray,
            buttons,
            loading: false
        })
    }

    /**
     * 保存数据处理函数
     * 此函数负责验证表单数据并根据是否存在ID来决定是创建新文档还是更新现有文档
     * 在保存成功后，更新组件状态并触发相应的回调函数
     */
    saveHandler = async () => {
        // 验证表单数据，如果验证失败，则停止执行后续操作
        if (!await this.validateFormData()) {
            return false
        }
        
        const formData = _.cloneDeep(this.state.formData)
        typeof this.props.beforeCreate === 'function' && await this.props.beforeCreate(formData)

        // 初始化响应对象和保存类型变量
        let response
        let saveType

        // 根据是否存在ID，决定执行更新操作还是创建操作
        if (this.props.id) {
            // 更新文档操作
            response = await updateDocumentById({
                serviceName: this.props.serviceName,
                collectionName: this.props.collectionName,
                id: this.props.id,
                content: formData
            })
            saveType = 'modify'
        } else {
            // 创建新文档操作
            response = await createDocument({
                serviceName: this.props.serviceName,
                collectionName: this.props.collectionName,
                content: formData
            })
            saveType = 'new'
        }

        // 根据响应结果，处理保存成功或失败的情况
        if (response && response.code === 200) {
            // 保存成功后，获取更新后的文档数据
            const newFormData = await getDocumentById({
                id: this.props.id || response.data.id,
                collectionName: this.props.collectionName,
                serviceName: this.props.serviceName
            })
            // 更新组件状态
            if (newFormData && newFormData.data) {
                this.setState({ 
                    auditFormData: newFormData.data,
                    formData: newFormData.data.content
                })
            }
            // 调用父组件传入的回调函数，如果存在的话
            typeof this.props.onDataCreate === 'function' && await this.props.onDataCreate(this.state, saveType)
            // 显示成功提示信息
            message.success('保存成功')
        } else {
            // 显示失败提示信息
            message.error('保存失败')
        }
    }


    /**
     * 表单变化时触发
     * this.props.onFormChange(originalFormData, changeFormData)
     * 外部可以接收onFormChange方法，originalFormData变化前的表单数据，changeFormData变化的表单数据
     * @param {*} key 变化的字段的key 
     * @returns 
     */
    onChange = (key) => {
        return async (value) => {
            const originalFormData = this.state.formData
            const changeFormData = { [key]: value }
            typeof this.props.onFormChange === 'function' && await this.props.onFormChange(originalFormData, changeFormData)
            this.setState(preState => {
                return {
                    formData: {
                        ...preState.formData,
                        ...changeFormData
                    }
                }
            })
            //对每一个关联变化的组件进行赋值
            Object.keys(changeFormData).forEach(item => {
                if (item !== key && this[item]) {
                    this[item].onChange(changeFormData[item], false)
                }
            })
        }
    }

    /**
     * 表单校验
     * validate(formData) 自定义表单校验方法
     */
    validateFormData = async () => {
        //先进行每个字段的基本校验
        let refArray = []
        this.state.propertyArray.forEach(item => {
            if (this.refMap[item.key]) {
                refArray.push(this.refMap[item.key])
            }
        })
        if (!await formValidate.validateForm(refArray)) {
            return false
        }

        //然后进行表单公共校验
        if (typeof this.props.validate === 'function' && !await this.props.validate(this.state.formData)) {
            return false
        }

        return true
    }

    /**
     * 表单字段渲染
     */
    renderProperties = () => {
        return this.state.propertyArray.map(item => {
            return (
                <BasicWidget
                    key={item.key}
                    formPage={this}
                    property={item}
                />
            )
        })
    }

    /**
     * 表单按钮渲染
     */
    renderButtons = () => {
        if (this.state.buttons.length === 0) {
            return ''
        }
        const buttonFloat = _.get(this, 'state.schema.buttonFloat', false)
        return (
            <FlexBox.Item
                span={12}
                style={{
                    display: 'flex',
                    justifyContent: 'center',
                    gap: '10px',
                    ...buttonFloat ? {
                        right: '10px',
                        top: '-45px',
                        position: 'absolute'
                    } : {
                        marginTop: '10px'
                    }
                }}
            >
                {
                    this.state.buttons.map(item => {
                        const showExpression = getFormProps(_.get(item, 'showExpression', true), this) //按钮显隐
                        if (!showExpression) return ''
                        return <Button
                            key={'btn_' + item.buttonName}
                            type={item.type}
                            title={item.buttonTitle}
                            style={item.style}
                            onClick={async () => {
                                if (typeof this.props[item.onClick] === 'function') {
                                    await this.props[item.onClick]()
                                } else if (typeof this[item.onClick] === 'function') {
                                    await this[item.onClick]()
                                } else {
                                    consoleUtil.log('[ButtonOnClick] Not found function Named ' + item.onClick)
                                }
                            }}
                        >{item.buttonName}</Button>
                    })
                }
            </FlexBox.Item>
        )
    }

    render() {
        if (this.state.loading === true) return <Spin />

        return (
            <Debug name='FormWidget'>
                <FlexBox.Box
                    key={this.state.formKey}
                    style={{
                        position: 'relative'
                    }}
                >
                    {this.renderProperties()}
                    {this.renderButtons()}
                </FlexBox.Box>
            </Debug>
        )
    }
}


/**
 * 基础组件，在所有组件的外部套一层来做一些公共的事情
 * @param {*} props {formPage, property}
 *  formPage FormWidget组件的指向
 *  property 表单字段的配置信息对象
 * @returns 
 */
function BasicWidget(props) {
    const { formPage, property } = props

    //组件只读
    const readOnly = formPage.props.readOnlyPage === true ? true : false

    //组件显隐
    const showExpression = getFormProps(_.get(property, 'widgetConfig.showExpression', true), formPage)

    //组件禁用
    const disabled = getFormProps(_.get(property, 'widgetConfig.disabled', false), formPage)

    //组件校验
    let rules = []
    const isMust = getFormProps(_.get(property, 'widgetConfig.isMust', false), formPage) //必做校验
    if (isMust === true || isMust === 'true') {
        rules.push({
            validate: formValidate.getValidater('isMust'),
            failMessage: `${property.description ? property.description : ''}不能为空`
        })
    }

    //公共的props
    const sharedProps = {
        prefixName: property.description ? { content: <span>{isMust && !disabled && !readOnly ? <span style={{ color: '#e11c1c', fontWeight: 'bolder' }}> * </span> : ''}{property.description}</span> } : null,
        onChange: formPage.onChange(property.key),
        ref: ref => { formPage.refMap[property.key] = ref },
        value: formPage.state.formData[property.key],
        disabled,
        readOnly,
        rules: !disabled && !readOnly ? rules : [] //禁用和只读的时候不进行校验
    }

    //计算组件跨度span
    let span = Number(_.get(property, 'span', 12))
    if (isNaN(span)) {
        span = 12
    }

    if (showExpression === false || showExpression === "false") {
        return ''
    } else {
        let Widget
        switch (property.widget) {
            case 'InputWidget': {
                Widget = <InputWidget
                    hiddenClearButton={getFormProps(_.get(property, 'widgetConfig.hiddenClearButton', null), formPage)}
                    placeholder={_.get(property, 'widgetConfig.placeholder', null)}
                    {...sharedProps}
                />
                break
            }
            case 'RadioWidget': {
                Widget = <RadioWidget
                    hiddenClearButton={getFormProps(_.get(property, 'widgetConfig.hiddenClearButton', null), formPage)}
                    paramCode={getFormProps(_.get(property, 'widgetConfig.paramCode', null), formPage)}
                    {...sharedProps}
                />
                break
            }
            case 'TextAreaWidget': {
                Widget = <TextAreaWidget
                    resize={getFormProps(_.get(property, 'widgetConfig.resize', null), formPage)}
                    rows={_.get(property, 'widgetConfig.rows', null)}
                    placeholder={_.get(property, 'widgetConfig.placeholder', null)}
                    {...sharedProps}
                />
                break
            }
            case 'DateWidget': {
                Widget = <DateWidget
                    {...sharedProps}
                />
                break
            }
            default: {
                Widget = ''
                break
            }
        }

        if (Widget) {
            return <FlexBox.Item span={span}>
                {Widget}
            </FlexBox.Item>
        }
    }
}

export default FormWidget
